package org.crown.common.interceptors;

import lombok.extern.slf4j.Slf4j;
import org.crown.common.annotation.EncryptEnable;
import org.crown.common.annotation.NotLogin;
import org.crown.common.cons.APICons;
import org.crown.common.jwt.JwtProperties;
import org.crown.common.jwt.JwtTokenUtil;
import org.crown.framework.responses.ResponseVo;
import org.crown.framework.spring.ApplicationUtils;
import org.crown.framework.utils.ResponseUtils;
import org.crown.project.api.BaseApi;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Objects;

/**
 * 通用拦截器
 *
 * @author Caratacus
 */
@Slf4j
@Component
public class ApiInterceptor extends HandlerInterceptorAdapter {

    @Autowired
    private JwtProperties jwtProperties;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            RestController restController = handlerMethod.getBeanType().getAnnotation(RestController.class);
            boolean isRest = Objects.nonNull(restController);
            ApplicationUtils.getRequest().setAttribute(APICons.API_REST, isRest);
            ResponseBody responseBody = handlerMethod.getMethodAnnotation(ResponseBody.class);
            boolean isRestResult = Objects.nonNull(responseBody);
            ApplicationUtils.getRequest().setAttribute(APICons.API_REST_RESULT, isRest || isRestResult);

            String path = request.getServletPath();
            boolean ifState = (path != null && path.startsWith(BaseApi.getApiPathPrefix()));
            if (ifState) {
                ifState = handlerMethod.getMethodAnnotation(NotLogin.class) != null || handlerMethod.getBeanType().getAnnotation(NotLogin.class) != null;
                if (!ifState) {
                    log.info("验证令牌");
                    if (verifyToken(request)) {
                        log.info("令牌无效");
                        ResponseUtils.printWriterResponseVo(response, ResponseVo.fail("令牌无效"));
                        return false;
                    }
                }

                // 判断是否要求解密
                ifState = handlerMethod.getMethodAnnotation(EncryptEnable.class) != null;
                if (ifState) {
                    String dataType = request.getParameter("dataType");
                    String aesData = request.getParameter("aesData");
                    String signData = request.getParameter("signData");
                    if (dataType == null || dataType.length() == 0 || aesData == null || aesData.length() == 0 || signData == null || signData.length() == 0) {
                        log.info("数据无效");
                        ResponseUtils.printWriterResponseVo(response, ResponseVo.fail("数据无效"));
                        return false;
                    }
                }
            }
        }
        return super.preHandle(request, response, handler);
    }

    /**
     * 验证token
     *
     * @return true:过期 false:没过期
     */
    private boolean verifyToken(HttpServletRequest request) {
        final String requestHeader = request.getHeader(jwtProperties.getHeader());
        if (requestHeader != null && requestHeader.startsWith(jwtProperties.getBearer() + " ")) {
            String authToken = requestHeader.substring(7);
            return jwtTokenUtil.isTokenExpired(authToken);
        } else {
            return true;
        }
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
        log.info("afterCompletion");
    }

}